<?php
namespace fast;
class AesUtil {
  /**
   * 微信转账到零钱回调验签
  * AES key
  *
  * @var string
  */
  private $aesKey;
  const KEY_LENGTH_BYTE = 32;
  const AUTH_TAG_LENGTH_BYTE = 16;
  /**
  * Constructor
  */
  public function __construct($aesKey) {
    if (strlen($aesKey) != self::KEY_LENGTH_BYTE) {
      throw new InvalidArgumentException('无效的ApiV3Key，长度应为32个字节');
    }
    $this->aesKey = $aesKey;
  }
 /**
  * Decrypt AEAD_AES_256_GCM ciphertext
  *
  * @param string    $associatedData     AES GCM additional authentication data
  * @param string    $nonceStr           AES GCM nonce
  * @param string    $ciphertext         AES GCM cipher text
  *
  * @return string|bool      Decrypted string on success or FALSE on failure
  */
  public function decryptToString($associatedData, $nonceStr, $ciphertext) {
    $ciphertext = \base64_decode($ciphertext);
    if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
      return false;
    }
    // ext-sodium (default installed on >= PHP 7.2)
    if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) {
      return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
    }
    // ext-libsodium (need install libsodium-php 1.x via pecl)
    if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available()) {
      return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
    }
    // openssl (PHP >= 7.1 support AEAD)
    if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
      $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
      $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
      return \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr,
      $authTag, $associatedData);
    }
    throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
  }



  public static function sign($content, $privateKeyPem, $charset) {  
      try {  
          $privateKey = openssl_pkey_get_private($privateKeyPem);  
          if (!$privateKey) {  
              throw new Exception("Invalid private key");  
          }  

          openssl_sign($content, $signature, $privateKey, OPENSSL_ALGO_SHA256);  
          return base64_encode($signature);  
      } catch (Exception $e) {  
          throw new RuntimeException("签名异常: " . $e->getMessage());  
      }  
  }  

  public static function verify($content, $sign, $publicKeyPem, $charset) {  
      try {  
          $publicKey = openssl_pkey_get_public($publicKeyPem);  
          if (!$publicKey) {  
              throw new Exception("Invalid public key");  
          }  

          $result = openssl_verify($content, base64_decode($sign), $publicKey, OPENSSL_ALGO_SHA256);  
          return $result === 1;  
      } catch (Exception $e) {  
          throw new RuntimeException("验签异常: " . $e->getMessage());  
      }  
  }  

  public static function encrypt($content, $publicKeyPem) {  
      try {  
          $publicKey = openssl_pkey_get_public($publicKeyPem);  
          if (!$publicKey) {  
              throw new Exception("Invalid public key");  
          }  

          openssl_public_encrypt($content, $encrypted, $publicKey);  
          return base64_encode($encrypted);  
      } catch (Exception $e) {  
          throw new RuntimeException("加密异常: " . $e->getMessage());  
      }  
  }  

  public static function decrypt($data, $privateKeyPem) {  
      try {  
          $privateKey = openssl_pkey_get_private($privateKeyPem);  
          if (!$privateKey) {  
              throw new Exception("Invalid private key");  
          }  

          openssl_private_decrypt(base64_decode($data), $decrypted, $privateKey);  
          return $decrypted;  
      } catch (Exception $e) {  
          throw new RuntimeException("解密异常: " . $e->getMessage());  
      }  
  }    

}